package com.zbkj.crmeb.store.service.impl;


import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.common.CommonPage;
import com.common.PageParamRequest;
import com.constants.Constants;
import com.crmeb.core.exception.CrmebException;
import com.crmeb.core.utils.TableNameUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.utils.CrmebUtil;
import com.utils.DateUtil;
import com.utils.vo.dateLimitUtilVo;
import com.zbkj.crmeb.chant.model.CategoryMatch;
import com.zbkj.crmeb.chant.model.ChannelMerchant;
import com.zbkj.crmeb.chant.service.ICategoryMatchService;
import com.zbkj.crmeb.chant.service.IChannelMerchantService;
import com.zbkj.crmeb.enums.CrowdCharacteristicsEnum;
import com.zbkj.crmeb.enums.ProductTypeEnum;
import com.zbkj.crmeb.store.dao.StoreProductDao;
import com.zbkj.crmeb.store.dao.StoreSaleAnalysisDao;
import com.zbkj.crmeb.store.model.*;
import com.zbkj.crmeb.store.request.StoreProductSearchRequest;
import com.zbkj.crmeb.store.response.StoreSaleAnalysisResponse;
import com.zbkj.crmeb.store.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class StoreSaleAnalysisServiceImpl extends ServiceImpl<StoreSaleAnalysisDao, StoreProductActive> implements StoreSaleAnalysisService {

    @Autowired
    private StoreSaleAnalysisDao storeSaleAnalysisDao;
    @Resource
    private StoreProductDao storeProductDao;
    @Autowired
    private StoreProductAttrValueService storeProductAttrValueService;
    @Autowired
    private ICategoryMatchService categoryMatchService;
    @Autowired
    private IChannelMerchantService channelMerchantService;
    @Autowired
    private SupplierService supplierService;

    /**
     * 功能描述: 查询商品概况信息
     *
     * @Param: [merId]
     * @Return: Map
     * @Author: duyb
     * @Date: 2022/10/14
     */
    @Override
    public Map getSurveyInfo(Integer merId) {
        //获取近一个月的活跃商品
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date daysAgo = getDaysAgo(new Date(), 30);
        List<StoreProductActive> nowList = this.list(Wrappers.<StoreProductActive>lambdaQuery()
                .between(StoreProductActive::getStatisticsDate, daysAgo, DateUtil.nowDateTimeReturnDate("yyyy-MM-dd"))
                .eq(StoreProductActive::getMerId, merId)
        );
        if (nowList == null) {
            return null;
        }
        //获取上月同比数据
        Date thirtyDate = getDaysAgo(daysAgo, 30);
        List<StoreProductActive> agoList = this.list(Wrappers.<StoreProductActive>lambdaQuery()
                .between(StoreProductActive::getStatisticsDate, thirtyDate, daysAgo)
                .eq(StoreProductActive::getMerId, merId)
        );
        BigDecimal nowPaymentAmount = new BigDecimal(0.00);
        Integer nowOrderNum = 0;
        BigDecimal nowRefundAmount = new BigDecimal(0.00);
        Integer nowRefundNum = 0;
        for (StoreProductActive storeProductActive : nowList) {
            nowOrderNum += storeProductActive.getPayProductNumber();
            nowPaymentAmount = nowPaymentAmount.add(storeProductActive.getPaymentAmount());
            nowRefundNum += storeProductActive.getRefundNumber();
            nowRefundAmount = nowRefundAmount.add(storeProductActive.getRefundAmount());
        }
        BigDecimal agoPaymentAmount = new BigDecimal(0.00);
        Integer agoOrderNum = 0;
        BigDecimal agoRefundAmount = new BigDecimal(0.00);
        Integer agoRefundNum = 0;
        for (StoreProductActive storeProductActive : agoList) {
            agoOrderNum += storeProductActive.getPayProductNumber();
            agoPaymentAmount = agoPaymentAmount.add(storeProductActive.getPaymentAmount());
            agoRefundNum += storeProductActive.getRefundNumber();
            agoRefundAmount = agoRefundAmount.add(storeProductActive.getRefundAmount());
        }
        BigDecimal orderNumRate = CrmebUtil.getRateDecimal(nowOrderNum, agoOrderNum);
        BigDecimal refundNumRate = CrmebUtil.getRateDecimal(nowRefundNum, agoRefundNum);
        BigDecimal paymentRate = CrmebUtil.getRateDecimal(nowPaymentAmount, agoPaymentAmount);
        BigDecimal refundRate = CrmebUtil.getRateDecimal(nowRefundAmount, agoRefundAmount);
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("orderNumRate", orderNumRate + "%");
        dataMap.put("orderNum", nowOrderNum);
        dataMap.put("agoOrderNum", agoOrderNum);
        dataMap.put("refundNumRate", refundNumRate + "%");
        dataMap.put("refundNum", nowRefundNum);
        dataMap.put("agoRefundNum", agoRefundNum);
        dataMap.put("paymentRate", paymentRate + "%");
        dataMap.put("paymentAmount", nowPaymentAmount);
        dataMap.put("agoPaymentAmount", agoPaymentAmount);
        dataMap.put("refundRate", refundRate + "%");
        dataMap.put("refundAmount", nowRefundAmount);
        dataMap.put("agoRefundAmount", agoRefundAmount);
        List<String> dateList = getListDate(30, 3);
        List<Map> list = new ArrayList<>();
        //循环获取折线图日期对应数据
        for (int i = 0; i < dateList.size(); i++) {
            String agoDate = "";
            try {
                agoDate = sdf.format(getDaysAgo(sdf.parse(dateList.get(i)), 2));
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
            Map infoMap = storeSaleAnalysisDao.getInfoByDate(merId, agoDate, dateList.get(i));
            if (infoMap == null) {
                infoMap = new HashMap();
                infoMap.put("refundNumber", null);
                infoMap.put("refundAmount", null);
                infoMap.put("payProductNumber", null);
                infoMap.put("paymentAmount", null);
            }
            infoMap.put("statisticsDate", dateList.get(i));
            list.add(infoMap);
        }
        dataMap.put("brokenLineInfo", list);
        return dataMap;
    }


    /**
     * 功能描述: 查询商品转化信息
     *
     * @Param: [merId]
     * @Return: Map
     * @Author: duyb
     * @Date: 2022/10/14
     */
    @Override
    public Map getConversionInfo(Integer merId) {
        //获取近一个月的活跃商品
        Date daysAgo = getDaysAgo(new Date(), 30);
        List<StoreProductActive> nowList = this.list(Wrappers.<StoreProductActive>lambdaQuery()
                .between(StoreProductActive::getStatisticsDate, daysAgo, DateUtil.nowDateTimeReturnDate("yyyy-MM-dd"))
                .eq(StoreProductActive::getMerId, merId)
        );
        if (nowList == null) {
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        //获取上月同比数据
        Date thirtyDate = getDaysAgo(daysAgo, 30);
        List<StoreProductActive> agoList = this.list(Wrappers.<StoreProductActive>lambdaQuery()
                .between(StoreProductActive::getStatisticsDate, thirtyDate, daysAgo)
                .eq(StoreProductActive::getMerId, merId)
        );
        Integer nowVisitorNum = 0;
        Integer nowAddPurchaseNum = 0;
        Integer nowPayProductNum = 0;
        for (StoreProductActive storeProductActive : nowList) {
            nowVisitorNum += storeProductActive.getVisitorNumber();
            nowAddPurchaseNum += storeProductActive.getAddPurchaseNumber();
            nowPayProductNum += storeProductActive.getPayProductNumber();
        }
        List<StoreProductActive> nowVisitorProductNumList = this.list(Wrappers.<StoreProductActive>lambdaQuery()
                .between(StoreProductActive::getStatisticsDate, thirtyDate, DateUtil.nowDateTimeReturnDate("yyyy-MM-dd"))
                .groupBy(StoreProductActive::getProductId)
                .eq(StoreProductActive::getMerId, merId)
        );
        Integer nowProductNum = nowVisitorProductNumList.size();
        Integer agoVisitorNum = 0;
        Integer agoAddPurchaseNum = 0;
        Integer agoPayProductNum = 0;
        for (StoreProductActive storeProductActive : agoList) {
            agoVisitorNum += storeProductActive.getVisitorNumber();
            agoAddPurchaseNum += storeProductActive.getAddPurchaseNumber();
            agoPayProductNum += storeProductActive.getPayProductNumber();
        }

        List<StoreProductActive> agoVisitorProductNumList = this.list(Wrappers.<StoreProductActive>lambdaQuery()
                .between(StoreProductActive::getStatisticsDate, thirtyDate, daysAgo)
                .groupBy(StoreProductActive::getProductId)
        );
        Integer agoProductNum = agoVisitorProductNumList.size();

        BigDecimal visitorRate = CrmebUtil.getRateDecimal(nowVisitorNum, agoVisitorNum);
        BigDecimal addPurchaseRate = CrmebUtil.getRateDecimal(nowAddPurchaseNum, agoAddPurchaseNum);
        BigDecimal payProductRate = CrmebUtil.getRateDecimal(nowPayProductNum, agoPayProductNum);
        BigDecimal productRate = CrmebUtil.getRateDecimal(nowProductNum, agoProductNum);
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("visitorNum", nowVisitorNum);
        dataMap.put("agoVisitorNum", agoVisitorNum);
        dataMap.put("visitorRate", visitorRate + "%");
        dataMap.put("addPurchaseNum", nowAddPurchaseNum);
        dataMap.put("agoAddPurchaseNum", agoAddPurchaseNum);
        dataMap.put("addPurchaseRate", addPurchaseRate + "%");
        dataMap.put("payProductNum", nowPayProductNum);
        dataMap.put("agoPayProductNum", agoPayProductNum);
        dataMap.put("payProductRate", payProductRate + "%");
        dataMap.put("productNum", nowProductNum);
        dataMap.put("agoProductNum", agoProductNum);
        dataMap.put("productRate", productRate + "%");
        List<String> dateList = getListDate(30, 3);
        List<Map> list = new ArrayList<>();
        //循环获取折线图日期对应数据
        for (int i = 0; i < dateList.size(); i++) {
            String agoDate = "";
            try {
                agoDate = sdf.format(getDaysAgo(sdf.parse(dateList.get(i)), 2));
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
            Map infoMap = storeSaleAnalysisDao.getProductByDate(merId, agoDate, dateList.get(i));

            if (infoMap == null) {
                infoMap = new HashMap();
                infoMap.put("visitorNumber", null);
                infoMap.put("addPurchaseNumber", null);
                infoMap.put("payProductNumber", null);
                infoMap.put("productNumber", null);
            }
            infoMap.put("statisticsDate", dateList.get(i));
            list.add(infoMap);
        }
        dataMap.put("brokenLineInfo", list);
        return dataMap;
    }

    /**
     * 功能描述: 查询商品滞销信息
     *
     * @Param: [merId]
     * @Return: Map
     * @Author: duyb
     * @Date: 2022/10/19
     */
    @Override
    public Map getUnsalableInfo(Integer merId) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        //获取在售商品数
        Integer cloudNumber = Optional.ofNullable(storeProductDao.selectCount(getQueryWrapper(true,merId))).orElse(0);
        Integer buildNumber = Optional.ofNullable(storeProductDao.selectCount(getQueryWrapper(false,merId))).orElse(0);
        Integer onSaleNumber=cloudNumber+buildNumber;
        //获取90天内有访问,有下单，有加购的商品
        String daysAgo = DateUtil.getDaysAgo(90);
        List<StoreProductActive> storeProductActiveList = this.list(Wrappers.<StoreProductActive>lambdaQuery()
                .groupBy(StoreProductActive::getProductId)
                .between(StoreProductActive::getStatisticsDate, daysAgo, DateUtil.nowDateTimeReturnDate("yyyy-MM-dd"))
                .eq(StoreProductActive::getMerId, merId)
        );
        List<Integer> productIdList = storeProductActiveList.stream().map(StoreProductActive::getProductId).collect(Collectors.toList());
        //获取滞销商品
        Integer unsalableNumber = onSaleNumber - productIdList.size();
        Map<String, Object> map = new HashMap<>();
        map.put("onSaleNumber", onSaleNumber);
        map.put("unsalableNumber", unsalableNumber);
        map.put("unsalableRate", getConversionRate(unsalableNumber, onSaleNumber) + "%");

        List<String> dateList = getListDate(30, 3);
        List<Map> list = new ArrayList<>();
        for (int i = 0; i < dateList.size(); i++) {
            String agoDate = "";
            try {
                agoDate = sdf.format(getDaysAgo(sdf.parse(dateList.get(i)), 90));
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
            //获取90天内有访问,有下单，有加购的商品id
            List<Integer> productIds = storeSaleAnalysisDao.getProductIdByDate(merId, agoDate, dateList.get(i));

            unsalableNumber = onSaleNumber - productIds.size();
            Map<String, Object> infoMap = new HashMap<>();
            infoMap.put("onSaleNumber", onSaleNumber);
            infoMap.put("unsalableNumber", unsalableNumber);
            infoMap.put("unsalableRate", (getConversionRate(unsalableNumber, onSaleNumber) + "%"));
            infoMap.put("statisticsDate", dateList.get(i));
            list.add(infoMap);
        }
        map.put("brokenLineInfo", list);
        return map;
    }

    /**
     * 功能描述: 查询商品销售明细
     *
     * @Param: [merId，pageParamRequest]
     * @Return: PageInfo<StoreSaleAnalysisResponse>
     * @Author: duyb
     * @Date: 2022/10/14
     */
    @Override
    public PageInfo<StoreSaleAnalysisResponse> getProductDetail(Integer merId, PageParamRequest pageParamRequest) {
        Page<StoreProductActive> pagetoreProductActive = PageHelper.startPage(pageParamRequest.getPage(), pageParamRequest.getLimit());
        Date daysAgo = getDaysAgo(new Date(), 30);
        List<StoreSaleAnalysisResponse> saleAnalysisResponseList = storeSaleAnalysisDao.getProductDetail(merId, daysAgo, DateUtil.nowDateTimeReturnDate("yyyy-MM-dd"));
        if (CollectionUtils.isEmpty(saleAnalysisResponseList)){
            return CommonPage.copyPageInfo(pagetoreProductActive, saleAnalysisResponseList);
        }
            List<Integer> productIds = saleAnalysisResponseList.stream().map(u -> u.getProductId()).distinct().collect(Collectors.toList());
            List<StoreProductAttrValue> attrValues = storeProductAttrValueService.list(Wrappers.<StoreProductAttrValue>lambdaQuery()
                    .in(StoreProductAttrValue::getProductId, productIds)
            );
            if (CollectionUtils.isNotEmpty(attrValues)){
                Map<Integer, StoreSaleAnalysisResponse> map = new HashMap<>();
                // 获取商品id
                for(StoreSaleAnalysisResponse storeSaleAnalysisResponse : saleAnalysisResponseList) {
                    int id = storeSaleAnalysisResponse.getProductId();
                    map.put(id, storeSaleAnalysisResponse);
                }
                // 配对商品图片
                for(StoreProductAttrValue attrValue : attrValues) {
                    StoreSaleAnalysisResponse response = map.get(attrValue.getProductId());
                    if(ObjectUtil.isNotNull(response)) {
                        response.setImage(attrValue.getImage());
                    }
                    response.setVisitorProductRate(getConversionRate(response.getAddPurchaseNumber(), response.getVisitorNumber()) + "%");
                    response.setVisitorpaymentRate(getConversionRate(response.getPayProductNumber(), response.getVisitorNumber()) + "%");
                }
            }
        return CommonPage.copyPageInfo(pagetoreProductActive, saleAnalysisResponseList);
    }

    /**
     * 功能描述: 获取转转化率
     *
     * @Param: [Integer]
     * @Return: BigDecimal
     * @Author: duyb
     * @Date: 2022/10/14
     */
    public BigDecimal getConversionRate(Integer i1, Integer i2) {
        BigDecimal b1 = new BigDecimal(i1);
        BigDecimal b2 = new BigDecimal(i2);
        //计算差值
        if (b2.compareTo(BigDecimal.ZERO) == 0) {
            //b2是0
            return BigDecimal.valueOf(0);
        }
        return b1.divide(b2, 3, BigDecimal.ROUND_DOWN).multiply(BigDecimal.TEN).multiply(BigDecimal.TEN).setScale(1);
    }

    /**
     * 功能描述: 获取指定日期n天前的日期
     *
     * @Param: [date，days]
     * @Return: Date
     * @Author: duyb
     * @Date: 2022/10/14
     */
    public Date getDaysAgo(Date date, Integer days) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, -24 * days);
        return calendar.getTime();
    }

    /**
     * 功能描述: 获取当前日期与n天前日期，指定间隔的日期集合
     *
     * @Param: [request]
     * @Return: List<String>
     * @Author: duyb
     * @Date: 2022/10/14
     */
    public List<String> getListDate(Integer data, Integer interval) {

        //获取30天的开始结束日期
        //时间计算
        String endTime = DateUtil.nowDateTime(Constants.DATE_FORMAT);
        String day = DateUtil.nowDateTime(Constants.DATE_FORMAT_START);
        String startTime = DateUtil.addDay(day, -data, Constants.DATE_FORMAT_START);

        dateLimitUtilVo dateLimit = new dateLimitUtilVo(startTime, endTime);

        //定义日期集合
        List<String> date = new ArrayList<>();

        //开始日期
        Date startDate = DateUtil.strToDate(dateLimit.getStartTime(), Constants.DATE_FORMAT);

        //结束日期
        Date endDate = DateUtil.strToDate(dateLimit.getEndTime(), Constants.DATE_FORMAT);

        while (endDate.after(startDate)) {
            date.add(DateUtil.dateToStr(startDate, Constants.DATE_FORMAT_DATE)); // 放入集合
            startDate = DateUtil.strToDate(DateUtil.addDay(startDate, interval, Constants.DATE_FORMAT), Constants.DATE_FORMAT); //循环一次 加一天
        }
        System.out.println(1);
        return date;
    }

    /**
     * 功能描述: 组装查询商品语句
     *
     * @Param: [inside，merId]
     * @Return: LambdaQueryWrapper
     * @Author: duyb
     * @Date: 2022/10/24
     */
    private LambdaQueryWrapper<StoreProduct> getQueryWrapper(boolean inside,Integer merId) {
        LambdaQueryWrapper<StoreProduct> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        ChannelMerchant channelMerchant = channelMerchantService.getById(merId);
        Supplier supplier = supplierService.getSupplierBarcode(merId);
        List<String> suppliersIdList = JSON.parseArray(channelMerchant.getSuppliersIds(), String.class);
        List<String> brandIdsList= JSON.parseArray(channelMerchant.getBrandIds(), String.class);
        List<String> tempIdList = JSON.parseArray(channelMerchant.getTempId(), String.class);
        if(CollectionUtils.isNotEmpty(brandIdsList)){
            lambdaQueryWrapper.in(StoreProduct::getBrandId,brandIdsList);
        }
        if(CollectionUtils.isNotEmpty(suppliersIdList)){
            if(null!=supplier){
                //商户如果是供应商的话 查询商户自建的商品 默认传入商户配置的供应商id
                suppliersIdList.add(supplier.getId().toString());
            }
        }
        if(CollectionUtils.isNotEmpty(tempIdList)){
            lambdaQueryWrapper.in(StoreProduct::getTempId,tempIdList);
        }

        if(inside) {
            lambdaQueryWrapper.eq(StoreProduct::getIsEurope, ProductTypeEnum.INSIDE).eq(StoreProduct::getMerId, merId);
        } else {
            //云仓 / 自建转云仓
            lambdaQueryWrapper.and(
                            a->a.ne(StoreProduct::getIsEurope, ProductTypeEnum.INSIDE)
                                    .or(b->b.eq(StoreProduct::getIsEurope, ProductTypeEnum.INSIDE)
                                            .ne(StoreProduct::getMerId,merId)
                                            .isNotNull(StoreProduct::getConvertIsEurope))
                    );
        }

        lambdaQueryWrapper.eq(StoreProduct::getIsShow, true);
        lambdaQueryWrapper.eq(StoreProduct::getIsDel, false);
        lambdaQueryWrapper.notInSql(StoreProduct::getId, "SELECT product_id FROM " + TableNameUtil.getProductMerName(merId) + " WHERE is_not_show = 1");
        lambdaQueryWrapper.gt(StoreProduct::getStock, 0);
        List<Integer> integerList = categoryMatchService.selectCategoryMatchDisable(merId).stream().map(CategoryMatch::getId).collect(Collectors.toList());
        lambdaQueryWrapper.notIn(CollectionUtils.isNotEmpty(integerList), StoreProduct::getCateId, integerList);
        return lambdaQueryWrapper;
    }

}
